import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:im_app/im/pojo/UiPojo.dart';
import 'package:im_app/im/util/DbUtil.dart';
import 'package:im_app/im/util/ImSingleton.dart';
import 'package:logger/logger.dart';

import '../../dao/ImGroupDao.dart';
import '../../dao/ImSessionDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../service/ContentSearchService.dart';
import '../../service/ImMessageSendService.dart';
import '../../util/MessageUtil.dart';
import '../../util/UiUtil.dart';
import '../sub/TransferMessagePage.dart';
import 'BaseBloc.dart';

final class TransferMessageCubit extends BaseBloc<TransferMessageEvent, TransferMessageState> {
  TransferMessageCubit(List<ImMessage> messages, TransferType transferType, TransferScene transferScene) :
        super(TransferMessageState.loading(messages, transferType, transferScene)) {
    on<TransferMessageLoadDataEvent>((event, emit){
      loadData(messages, state.transferType, state.transferScene);
    });
    on<TransferMessageChangeSelectTypeEvent>((event, emit){
      _changeSelectType(state, event.selectType);
    });
    on<TransferMessageSearchableEvent>((event, emit){
      _searchable(state, event.searable);
    });
    on<TransferMessageSessionSearchEvent>((event, emit){
      _sessionSearch(state, event.search);
    });
    on<TransferMessageSearchEvent>((event, emit){
      _search(state, event.search);
    });
    on<TransferMessageAddSessionEvent>((event, emit){
      _addSession(state, event.session);
    });
    on<TransferMessageRemoveSessionEvent>((event, emit){
      _removeSession(state, event.session);
    });
    on<TransferMessageSelectSessionEvent>((event, emit){
      _selectSession(state, event.session);
    });
    on<TransferMessageCancelTransferEvent>((event, emit){
      _cancelTransfer(state, event.context, event.isCreateSession);
    });
    on<TransferMessageSubmitEvent>((event, emit) async {
      await _transferMessages(state, event.context, event.isCreateSession);

    });
    on<TransferMessageLeaveMessageChangeEvent>((event, emit){
      _leaveMessage(state, event.leaveMessage);
    });
  }

  final _logger = Logger(printer: PrettyPrinter(),);

  Future<void> loadData(List<ImMessage> messages, TransferType transferType, TransferScene transferScene) async {
    var sessionDao = ImSessionDao();
    var groupDao = ImGroupDao();
    var userId = ImSingleton.getInstance().session.userId!;
    var startDate = DateTime.now().add(const Duration(days: -1000));
    List<ImSession> sessions = await sessionDao.getByUserIdAndTimeAndSize(userId, startDate, 0, 500);
    if (sessions.isNotEmpty) {
      for (var session in sessions) {
        if (session.groupCode != null) {
          session.group = await groupDao.getByCodeAndUserId(session.groupCode!, userId);
        }
      }
      sessionDao.sort(sessions);
    }
    emit(TransferMessageState.success(messages, sessions, transferType, transferScene));
  }

  void _changeSelectType(TransferMessageState oldState, SelectType selectType) {
    emit(oldState.copy(selectType: selectType));
  }

  void _searchable(TransferMessageState oldState, bool searchable) {
    emit(oldState.copy(searchable: searchable, searchResultSet: SearchResultSet(), contentSearch: ''));
  }

  void _sessionSearch(TransferMessageState oldState, String search) {
    var searchSessions = oldState.allSessions.where((session)=>session.name!.contains(search)).toList(growable: false);
    emit(oldState.copy(filterSessions: searchSessions, contentSearch: search));
  }

  void _search(TransferMessageState oldState, String search) async {
    var contentSearchService = ContentSearchService();
    var userId = ImSingleton.getInstance().session.userId;
    if (search == '') {
      emit(oldState.copy(searchResultSet: SearchResultSet(), contentSearch: ''));
      return;
    }
    List<SearchResult> userSearchResults = await contentSearchService.searchUsers(search);
    List<SearchResult> groupSearchResults = await contentSearchService.searchGroups(userId!, search);
    var searchResultSet = SearchResultSet(userSearchResults: userSearchResults, groupSearchResults: groupSearchResults);

    var searchSessions = oldState.copy(searchResultSet: searchResultSet, contentSearch: search);
    emit(searchSessions);
  }

  void _addSession(TransferMessageState oldState, ImSession session) {
    var isExisted = oldState.selectedSessions.contains(session);
    var sessions = oldState.selectedSessions;
    if (!isExisted) {
      var selectedSessions = copyList(oldState.selectedSessions);
      selectedSessions.add(session);
      sessions = selectedSessions;
    }
    emit(oldState.copy(selectedSessions: sessions));
  }

  void _removeSession(TransferMessageState oldState, ImSession session) {
    var isExisted = oldState.selectedSessions.contains(session);
    var sessions = oldState.selectedSessions;
    if (isExisted) {
      var selectedSessions = copyList(oldState.selectedSessions);
      selectedSessions.remove(session);
      sessions = selectedSessions;
    }
    emit(oldState.copy(selectedSessions: sessions));
  }

  void _selectSession(TransferMessageState oldState, ImSession session) {
    emit(oldState.copy(selectedSession: session, showTransferPane: true, isTransferPaneFlush: false));
  }

  void _cancelTransfer(TransferMessageState oldState, BuildContext context, bool isCreateSession) {
    if (oldState.transferScene.sceneType == TransferSceneType.message && !isCreateSession) {
      emit(oldState.copy(showTransferPane: false, isTransferPaneFlush: true));
    } else {
      emit(oldState.copy(showTransferPane: false, isTransferPaneFlush: true));
      Navigator.of(context).pop();
    }
  }

  void _leaveMessage(TransferMessageState oldState, String leaveMessage) {
    emit(oldState.copy(leaveMessage: leaveMessage, isTransferPaneFlush: true));
  }

  Future<void> _transferMessages(TransferMessageState oldState, BuildContext context, bool isCreateSession) async {
    var selectType = oldState.selectType;
    var selectedSessions = oldState.selectedSessions;
    var selectedSession = oldState.selectedSession;
    var transferMessages = oldState.messages;
    var leaveMessage = oldState.leaveMessage;

    if (selectType == SelectType.simple && selectedSession != null) { // 转发给单个聊天
      var messageSendService = ImMessageSendService();

      for (var transferMessage in transferMessages) {
        changeSessionInfo(transferMessage, selectedSession!, leaveMessage);

        var message = await buildImMessage(selectedSession, transferMessage, messageSendService);
        var leaveImMessage = await buildLeaveMessage(selectedSession, leaveMessage, messageSendService);

        var messages = [message];
        if (leaveImMessage != null) messages.add(leaveImMessage!);

        await messageSendService.sendMessage([selectedSession], messages);

        UiUtil.uiShowSession(selectedSession);
      }
    } else if (selectType == SelectType.multiple && (selectedSessions?.isNotEmpty??false)) { // 转发多个聊天
      var messageSendService = ImMessageSendService();

      var messages = <ImMessage>[];
      var sessions = <ImSession>[];
      for (var session in selectedSessions!) {
        for (var transferMessage in transferMessages) {
          changeSessionInfo(transferMessage, session!, leaveMessage);

          var message = await buildImMessage(session, transferMessage, messageSendService);
          var leaveImMessage = await buildLeaveMessage(session, leaveMessage, messageSendService);

          messages.add(message);
          if (leaveImMessage != null) messages.add(leaveImMessage!);

          sessions.add(session);
        }
      }
      await messageSendService.sendMessage(sessions, messages);

      // Navigator.of(context).popUntil(ModalRoute.withName("/MessageSendPage"));
      sessions.forEach((session)=>{
        UiUtil.uiChangeSession(session)
      });
      // UiUtil.showSnackBar(context, '消息转发成功');
    }

    var session = oldState.messages[0].imSession;
    if (session == null) {
      var sessionDao = ImSessionDao();
      session = await sessionDao.getById(oldState.messages[0].sessionId!);
    }

    if (oldState.transferScene.sceneType == TransferSceneType.message) {
      // emit(oldState.copy(forwardSession: session, forwardUrl: "/MessageSendPage", showTransferPane: false));
      Navigator.of(context).popUntil(ModalRoute.withName("/MessageSendPage"));

      UiUtil.showSnackBar(context, '消息转发成功');
    } else if (oldState.transferScene.sceneType == TransferSceneType.collect) {
      // emit(oldState.copy(forwardSession: session, forwardUrl: "/CollectInfoPage", showTransferPane: false));
      Navigator.of(context).popUntil(ModalRoute.withName("/CollectInfoPage"));

      UiUtil.showSnackBar(context, '消息转发成功');
    } else {
      print('error!!!!!!!!!, 不支持这种类型：${oldState.transferScene.sceneType}');
    }

  }

  changeSessionInfo(ImMessage imMessage, ImSession imSession, String leaveMessage) {
    imSession.updateTime = DateTime.now();

    var content = imMessage.content??'';

    var imMessageType = imMessage.messageType;

    if(leaveMessage != '') {
      imSession.latelyMessage = MessageUtil.buildLastedMessage(imMessageType, leaveMessage);
    } else {
      imSession.latelyMessage = MessageUtil.buildLastedMessage(imMessageType, content);
    }
  }

  // 构建留言
  Future<ImMessage?> buildLeaveMessage(ImSession imSession, String leaveMessage,
      ImMessageSendService messageSendService) async {

    ImMessage? leaveImMessage = null;
    if(leaveMessage != '') {
      leaveImMessage = await messageSendService.buildMessage(imSession, leaveMessage, ImMessageType.Text, null);
    }
    return leaveImMessage;
  }

  Future<List<ImMessage>> buildImMessages(ImSession session, List<ImMessage> imMessages,
      ImMessageSendService messageSendService) async {
    var result = <ImMessage>[];
    for (var imMessage in imMessages) {
      var newMessage = await buildImMessage(session, imMessage, messageSendService);
      result.add(newMessage);
    }
    return result;
  }

  Future<ImMessage> buildImMessage(ImSession session, ImMessage imMessage,
      ImMessageSendService messageSendService) async {

    var content = imMessage.content??'';
    var imMessageType = imMessage.messageType;
    var refMessages = imMessage.refMessages;

    var message = await messageSendService.buildMessage(session, content, imMessageType, refMessages);
    return message;
  }
}

final class TransferMessageState extends Equatable {
  final LoadingState state;
  final List<ImMessage> messages;
  final List<ImSession> allSessions;
  final List<ImSession> filterSessions;
  final String contentSearch;
  final SearchResultSet? searchResultSet;
  final SearchResult? selectSearchResult;
  final ImSession? selectedSession;         // 单选
  final List<ImSession> selectedSessions;   // 多选
  final String errorMsg;
  final SelectType selectType;
  final String leaveMessage;                // 留言
  final bool searchable;
  final bool showTransferPane;
  final bool isTransferPaneFlush;
  final TransferType transferType;
  final String? forwardUrl;
  final ImSession? forwardSession;
  final TransferScene transferScene;       // 转发场景

  TransferMessageState._({
    this.state = LoadingState.loading,
    required this.messages,
    required this.transferScene,
    this.allSessions = const <ImSession>[],
    this.filterSessions = const <ImSession>[],
    this.contentSearch = '',
    this.selectedSessions = const <ImSession>[],
    this.errorMsg = '',
    this.selectType = SelectType.simple,
    this.leaveMessage = '',
    this.searchable = false,
    this.selectedSession = null,
    this.showTransferPane = false,
    this.isTransferPaneFlush = false,
    this.searchResultSet,
    this.selectSearchResult = null,
    this.transferType = TransferType.simple,
    this.forwardUrl = null,
    this.forwardSession = null,
  });

  TransferMessageState copy({List<ImMessage>? messages, List<ImSession>? allSessions, List<ImSession>? filterSessions,
    List<ImSession>? selectedSessions, ImSession? selectedSession, SelectType? selectType, bool? searchable,
    String? contentSearch, String? errorMsg, bool? showTransferPane, SearchResultSet? searchResultSet,
    SearchResult? selectSearchResult, String? leaveMessage, TransferType? transferType, String? forwardUrl,
    ImSession? forwardSession, TransferScene? transferScene, bool? isTransferPaneFlush}) {
    return TransferMessageState._(
      messages: messages?? this.messages,
      allSessions: allSessions?? this.allSessions,
      filterSessions: filterSessions ?? this.filterSessions,
      selectedSession: selectedSession ?? this.selectedSession,
      selectedSessions: selectedSessions?? this.selectedSessions,
      selectType: selectType ?? this.selectType,
      leaveMessage: leaveMessage ?? this.leaveMessage,
      searchable: searchable ?? this.searchable,
      contentSearch: contentSearch?? this.contentSearch,
      errorMsg: errorMsg?? this.errorMsg,
      state: this.state,
      showTransferPane: showTransferPane ?? this.showTransferPane,
      isTransferPaneFlush: isTransferPaneFlush ?? this.isTransferPaneFlush,
      searchResultSet: searchResultSet ?? this.searchResultSet,
      selectSearchResult: selectSearchResult ?? this.selectSearchResult,
      transferType: transferType ?? this.transferType,
      forwardUrl: forwardUrl ?? this.forwardUrl,
      forwardSession: forwardSession ?? this.forwardSession,
      transferScene: transferScene ?? this.transferScene,
    );
  }

  TransferMessageState.loading(List<ImMessage> messages, TransferType transferType, TransferScene transferScene) :
        this._(messages: messages, transferType: transferType, transferScene: transferScene);

  TransferMessageState.success(List<ImMessage> messages, List<ImSession> sessions, TransferType transferType, TransferScene transferScene) :
    this._(messages: messages, allSessions: sessions, filterSessions: sessions, state: LoadingState.success,
      transferType: transferType, transferScene: transferScene);

  @override
  List<Object?> get props => [state, messages, filterSessions, contentSearch, selectedSessions, selectedSession,
    selectType, searchable, errorMsg, showTransferPane, leaveMessage, isTransferPaneFlush];
}

abstract class TransferMessageEvent {}
class TransferMessageLoadDataEvent extends TransferMessageEvent {}
class TransferMessageChangeSelectTypeEvent extends TransferMessageEvent {
  SelectType selectType;
  TransferMessageChangeSelectTypeEvent(this.selectType);
}
class TransferMessageSearchableEvent extends TransferMessageEvent {
  final bool searable;
  TransferMessageSearchableEvent(this.searable);
}
class TransferMessageSessionSearchEvent extends TransferMessageEvent {
  final String search;
  TransferMessageSessionSearchEvent(this.search);
}
class TransferMessageSearchEvent extends TransferMessageEvent {
  final String search;
  TransferMessageSearchEvent(this.search);
}
class TransferMessageAddSessionEvent extends TransferMessageEvent {
  final ImSession session;
  TransferMessageAddSessionEvent(this.session);
}
class TransferMessageRemoveSessionEvent extends TransferMessageEvent {
  final ImSession session;
  TransferMessageRemoveSessionEvent(this.session);
}
class TransferMessageSelectSessionEvent extends TransferMessageEvent {
  final ImSession session;
  TransferMessageSelectSessionEvent(this.session);
}
class TransferMessageCancelTransferEvent extends TransferMessageEvent {
  final BuildContext context;
  final bool isCreateSession;
  TransferMessageCancelTransferEvent(this.context, this.isCreateSession);
}
class TransferMessageSubmitEvent extends TransferMessageEvent {
  final BuildContext context;
  final bool isCreateSession;
  TransferMessageSubmitEvent(this.context, this.isCreateSession);
}
class TransferMessageLeaveMessageChangeEvent extends TransferMessageEvent {
  final String leaveMessage;
  TransferMessageLeaveMessageChangeEvent(this.leaveMessage);
}




enum TransferType {
  simple,          // 单个消息转发
  oneByeOne,       // 批量转发之逐条发送
  mergeOne,        // 批量转发之合并发送
}